/**
 * @file cv_example_013.cpp
 * @author 逆流 (1171267147@qq.com)
 * @brief 离散傅里叶变换
 * @version 0.1
 * @date 2024-07-05
 *
 * @copyright Copyright (c) 2024.
 * @ref
 * https://docs.opencv.org/4.x/d8/d01/tutorial_discrete_fourier_transform.html
 *
 */

#include <iostream>
#include <opencv2/opencv.hpp>

#include "env.h"

using std::cout;
using std::endl;
using namespace cv;

int main(int argc, char** argv) {
    samples::addSamplesDataSearchPath(kResourcesDir);

    CommandLineParser parser(argc, argv, "{@input | lena.jpg | input image}");

    Mat src = imread(samples::findFile(parser.get<String>("@input")), IMREAD_GRAYSCALE);
    if (src.empty()) {
        cout << "Could not open or find the image!\n" << endl;
        parser.printMessage();
        return EXIT_FAILURE;
    }

    resize(src, src, Size(), 0.25, 0.25);

    Mat padded;
    int m = getOptimalDFTSize(src.rows);
    int n = getOptimalDFTSize(src.cols);
    copyMakeBorder(src, padded, 0, m - src.rows, 0, n - src.cols, BORDER_CONSTANT, Scalar::all(0));

    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complex_src;
    merge(planes, 2, complex_src);

    dft(complex_src, complex_src);

    split(complex_src, planes);
    magnitude(planes[0], planes[1], planes[0]);

    Mat mag_src = planes[0];
    mag_src += Scalar::all(1);
    log(mag_src, mag_src);

    mag_src = mag_src(Rect(0, 0, mag_src.cols & -2, mag_src.rows & -2));

    int cx = mag_src.cols / 2;
    int cy = mag_src.rows / 2;

    Mat q0(mag_src, Rect(0, 0, cx, cy));
    Mat q1(mag_src, Rect(cx, 0, cx, cy));
    Mat q2(mag_src, Rect(0, cy, cx, cy));
    Mat q3(mag_src, Rect(cx, cy, cx, cy));

    Mat tmp;
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);

    q1.copyTo(tmp);
    q2.copyTo(q1);
    tmp.copyTo(q2);

    normalize(mag_src, mag_src, 0, 1, NORM_MINMAX);

    imshow("Source", src);
    imshow("DFT", mag_src);

    waitKey();

    destroyAllWindows();

    return EXIT_SUCCESS;
}
